import asyncio
import sys
import time
from pathlib import Path

import vlc
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QVBoxLayout, QHBoxLayout, \
    QListWidgetItem, QListWidget, QInputDialog

from config import VIDEO_CACHE_PATH
from downloader import download_bv
from loader import load_video_json, add_bv_to_json
from util import get_true_bv


class VideoDownloader(QThread):

    downloadFinishSignal = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.loop = None
        self.bv_queue = asyncio.Queue()

    def run(self) -> None:
        self.loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self.loop)
        self.loop.run_until_complete(self.start_download())
        self.loop.run_forever()

    async def start_download(self):
        while True:
            handle_bv = await self.bv_queue.get()
            bv, index = get_true_bv(handle_bv)
            try:
                # 判断一下BV是否存在
                bv_path = VIDEO_CACHE_PATH / f"{handle_bv}.mp4"
                if bv_path.exists():
                    continue
                await download_bv(bv, index)
                self.downloadFinishSignal.emit(handle_bv)
            except Exception as e:
                print(str(e) + handle_bv)
            finally:
                pass

    def push_bv(self, bv):
        self.loop.call_soon_threadsafe(self.bv_queue.put_nowait, bv)


class VideoPlayer(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.play_next_button = None
        self.add_bv_button = None
        self.pause_button = None
        self.play_button = None
        self.video_list_widget = None
        self.downloadVideoThread = None

        self.lastSwitchVideoTime = -1

        self.init_download_video_thread()

        self.setGeometry(0, 0, 1200, 800)

        self.video_bvs, self.video_infos = load_video_json()
        self.now_bv = None

        self.video_widget = VideoWidget()
        self.video_widget.mediaPlayerEndReachedSignal.connect(self.onVideoPlayerEndReached)
        self.setup_ui()

        self.play_bv(self.video_bvs[0])
        self.populate_video_list()

    def setup_ui(self):
        # 创建主布局
        main_layout = QHBoxLayout()

        # 创建左侧布局
        left_layout = QVBoxLayout()

        button_layout = QHBoxLayout()

        self.play_button = QPushButton("播放/暂停")
        self.play_next_button = QPushButton("下个视频")
        self.add_bv_button = QPushButton("添加BV")

        button_layout.addWidget(self.play_button)
        button_layout.addWidget(self.play_next_button)
        button_layout.addWidget(self.add_bv_button)
        left_layout.addWidget(self.video_widget)
        left_layout.addLayout(button_layout)

        right_layout = QVBoxLayout()
        self.video_list_widget = QListWidget()
        self.video_list_widget.setFixedWidth(300)
        self.video_list_widget.itemClicked.connect(self.onVideoListItemClicked)
        right_layout.addWidget(self.video_list_widget)

        main_layout.addLayout(left_layout)
        main_layout.addLayout(right_layout)

        self.setLayout(main_layout)

        self.play_button.clicked.connect(self.video_widget.startOrPause)
        self.play_next_button.clicked.connect(self.play_next_bv)
        self.add_bv_button.clicked.connect(self.add_bv)

    def init_download_video_thread(self):
        self.downloadVideoThread = VideoDownloader()
        self.downloadVideoThread.downloadFinishSignal.connect(self.onVideoDownloadFinish)
        self.downloadVideoThread.start()

    def populate_video_list(self):
        self.video_list_widget.clear()
        for bv in self.video_bvs:
            item = QListWidgetItem(self.video_infos[bv]['title'])
            item.setData(Qt.UserRole, bv)
            self.video_list_widget.addItem(item)

    def onVideoListItemClicked(self, item):
        bv = item.data(Qt.UserRole)  # 获取存储的 BV 号
        self.play_bv(bv)

    def play_bv(self, bv):
        bv_path = VIDEO_CACHE_PATH / f"{bv}.mp4"
        if not bv_path.exists():
            # asyncio.get_event_loop().run_until_complete(download_bv(bv))
            # 放到另一条线程里现在
            self.downloadVideoThread.push_bv(bv)
        else:
            timeStamp = time.time()
            if timeStamp - self.lastSwitchVideoTime < 1:
                return
            self.lastSwitchVideoTime = timeStamp
            self.video_widget.setMedia(bv_path)
            self.now_bv = bv

    def play_next_bv(self):
        for index, bv in enumerate(self.video_bvs):
            if bv == self.now_bv:
                if index == len(self.video_bvs) - 1:
                    self.play_bv(self.video_bvs[0])
                else:
                    self.play_bv(self.video_bvs[index+1])
                next_next_bv_path = VIDEO_CACHE_PATH / f"{self.video_bvs[index+2]}.mp4"
                if not next_next_bv_path.exists():
                    # 放到另一条线程里现在
                    self.downloadVideoThread.push_bv(self.video_bvs[index+2])
                break

    def add_bv(self):
        value, ok = QInputDialog.getText(self, "请输入", "请输入BV号")
        if ok:
            if "?" in value:
                bv = value.split("?")[0].replace("https://www.bilibili.com/video/", "")
                index = int(value.split("?")[1].split("&")[0].replace("p=", "")) - 1
            elif "#" in value:
                bv = value.split("#")[0]
                index = value.split("#")[1]
            else:
                bv = value
                index = 0
            if add_bv_to_json(bv, index):
                self.video_bvs, self.video_infos = load_video_json()
                self.populate_video_list()

    def onVideoPlayerEndReached(self):
        self.play_next_bv()

    def onVideoDownloadFinish(self, bv):
        pass


class VideoWidget(QWidget):

    mediaPlayerEndReachedSignal = pyqtSignal()

    def __init__(self, instance=vlc.Instance()):
        super().__init__()

        self.hardwareDecode = True  # 硬解
        self.media = None  # 媒体
        self.audioChannel = 0  # 0 原始音效  5 杜比音效
        self.hiding = False  # 隐藏
        self.progress = 0  # 视频进度
        self.pause = True  # 是否暂停
        self.volume = 100
        self.video = ""
        self.video_list = []

        self.instance = instance
        self.player = None

        self.initVlc()

    def initVlc(self):
        """初始化Vlc"""
        self.player = self.instance.media_player_new()
        self.player.video_set_mouse_input(False)
        self.player.video_set_key_input(False)
        self.player.event_manager().event_attach(vlc.EventType(265), self.mediaPlayerEndReached)
        self.player.set_hwnd(self.winId())

    def mediaPlayerEndReached(self, event):
        """视频播放完"""
        self.mediaPlayerEndReachedSignal.emit()

    def autoWindowSize(self, video_path):
        """窗口大小自适应"""
        pass

    def setMedia(self, video_path: Path):
        """设置视频"""
        if self.hardwareDecode:
            self.media = self.instance.media_new(video_path, 'avcodec-hw=any')  # 设置vlc并硬解播放
        else:
            self.media = self.instance.media_new(video_path, 'avcodec-hw=none')  # 软解  vlc3.0似乎不起作用?
        self.player.set_media(self.media)  # 设置视频
        self.player.audio_set_channel(self.audioChannel)
        self.player.play()
        self.autoWindowSize(video_path)
        self.video = video_path.__str__()
        self.pause = False

    def setAudio(self, volume: int):
        """设置音量"""
        self.volume = volume
        self.player.audio_set_volume(volume)

    def startOrPause(self):
        if self.pause:
            self.startVideo()
        else:
            self.pauseVideo()

    def pauseVideo(self):
        """暂停视频"""
        if self.pause:
            return
        self.progress = self.player.get_time()
        self.pause = True
        self.player.pause()

    def startVideo(self):
        """播放视频"""
        if not self.pause:
            return
        self.pause = False
        self.player.set_pause(0)

    def setTime(self, progress):
        """设置视频进度"""
        self.player.set_time(progress)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = VideoPlayer()
    window.show()
    sys.exit(app.exec_())
